/**
 * 
 */
package com.aspect;

import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.dto.RespBase;
import com.entity.User;
import com.exception.ExceptionI18Message;
import com.exception.ServiceException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.service.UserService;

/**
 *
 * @类名称：ResponseFormatAspect.java
 * @类描述：返回值通用数据格式切面
 * @创建人：zhongy
 * @创建时间：2017年4月5日-上午11:53:39
 * @修改备注:
 * @version
 */
@Aspect
@Component
public class ResponseFormatAspect {
	static Logger logger = Logger.getLogger(ResponseFormatAspect.class);
//	private static final String REDIS_ANN_POINTCUT = "@annotation(com.wn.aspect.ResponseFormat)";
	@Resource
	private UserService userService;

//	@Pointcut(value = REDIS_ANN_POINTCUT) // 切面传递方法，没有什么作用只为了代码优雅
//	public void format() {// 格式化的相关方法
//		logger.info("data format aspect");
//	}

	@Around("execution(* com.controller..*.*(..))")
	public Object formatImpl(ProceedingJoinPoint pjp) throws Throwable {

		/**
		 * step1、调用方法获取执行结果
		 * step2、获取执行过程中出现的异常 
		 * step3、返回值包装
		 * 
		 * 
		 */
		try {
			long uuid = System.currentTimeMillis() + (int) (Math.random() * 1000);
			Gson gson = null;
			GsonBuilder gsonBuilder = new GsonBuilder();
			gsonBuilder.serializeSpecialFloatingPointValues();
			gson = gsonBuilder.create();

			long startTimeMillis = System.currentTimeMillis();
			RequestAttributes ra = RequestContextHolder.getRequestAttributes();
			ServletRequestAttributes sra = (ServletRequestAttributes) ra;
			HttpServletRequest request = sra.getRequest();
			Map<?, ?> inputParamMap = request.getParameterMap();
			// 获取请求地址
			String requestPath = request.getRequestURI();
			StringBuffer sb = new StringBuffer();
			Object[] args = pjp.getArgs();
			if (args != null) {
				for (Object obj : args) {
					if (obj instanceof HttpServletResponse)
						continue;
					if (obj instanceof HttpServletRequest) {
						continue;
					}
					sb.append(gson.toJson(obj));
				}
			}
			for (Enumeration<String> headerNames = request.getHeaderNames(); headerNames.hasMoreElements();) {
				String headerName = headerNames.nextElement();
				String value = request.getHeader(headerName);
				if (headerName.equalsIgnoreCase("Cookie"))
					sb.append(headerName).append(":").append(value).append(" ");
			}
			logger.info(uuid + "请求地址：" + requestPath + "  参数：" + gson.toJson(inputParamMap) + "  输入：" + sb.toString());

			ResponseFormat auth = getControllerMthodNeedLogin(pjp);
			if (auth == null || auth.needLogin()) {
				Cookie uidcookie = getCookieByName(request, "uid");
				Cookie typecookie = getCookieByName(request, "lt");
				Cookie oauth = getCookieByName(request, "oauth");
				Cookie tokencookie = getCookieByName(request, "token");
				if (uidcookie == null || typecookie == null || tokencookie == null) {
					return new RespBase(RespBase.STATUS_ERR_COOKIE_EMPTY, "认证参数为空,请重新登录");
				}
				long uid = Long.parseLong(uidcookie.getValue());
				int type = Integer.valueOf(typecookie.getValue());
				String token = tokencookie.getValue().toString();
				String oauthvalue = oauth == null ? null : oauth.getValue().toString();
				User user = userService.getUserByCookie(uid, type, oauthvalue, token);
				if (user == null) {
					return new RespBase(RespBase.STATUS_ERR_TOKEN, "认证失败,请重新登录");
				}
			}

			// 执行完方法的返回值：调用proceed()方法，就会触发切入点方法执行
			Object t = pjp.proceed();// 执行结果

			long endTimeMillis = System.currentTimeMillis();
			String json = gson.toJson(t);
			if (json.length() > 300)
				json = json.substring(0, 300) + "...";

			logger.info(
					uuid + "处理时间：" + (endTimeMillis - startTimeMillis) + "ms ;" + " " + requestPath + " 返回：" + json);
			return new RespBase(t);
		} catch (IllegalArgumentException e) {// 捕获以后进行返回
			
				return new RespBase(RespBase.STATUS_ERR_PARAM_ILLEGAL,  ExceptionI18Message.getLocaleMessage(e.getMessage()));
			
			
			
		} catch (ServiceException e1) {
			return new RespBase(e1.code, ExceptionI18Message.getLocaleMessage(e1.getMessage(),e1.args));
		} catch (Exception e2) {// 其他其他不可预知的错误
			if(e2 instanceof ServiceException){
				System.out.println(e2);
			}
			return new RespBase(RespBase.STATUS_ERR_SYSTEM, ExceptionI18Message.getLocaleMessage(e2.getMessage()));
		}

	}

	public static ResponseFormat getControllerMthodNeedLogin(JoinPoint joinPoint) throws Exception {
		String targetName = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		Object[] arguments = joinPoint.getArgs();
		Class targetClass = Class.forName(targetName);
		Method[] methods = targetClass.getMethods();
		ResponseFormat needLogin = null;
		for (Method method : methods) {
			if (method.getName().equals(methodName)) {
				Class[] clazzs = method.getParameterTypes();
				if (clazzs.length == arguments.length) {
					needLogin = method.getAnnotation(ResponseFormat.class);
					break;
				}
			}
		}
		return needLogin;
	}

	/**
	 * 根据名字获取cookie
	 * 
	 * @param request
	 * @param name
	 *            cookie名字
	 * @return
	 */
	public static Cookie getCookieByName(HttpServletRequest request, String name) {
		Map<String, Cookie> cookieMap = ReadCookieMap(request);
		if (cookieMap.containsKey(name)) {
			Cookie cookie = (Cookie) cookieMap.get(name);
			return cookie;
		} else {
			return null;
		}
	}

	/**
	 * 将cookie封装到Map里面
	 * 
	 * @param request
	 * @return
	 */
	private static Map<String, Cookie> ReadCookieMap(HttpServletRequest request) {
		Map<String, Cookie> cookieMap = new HashMap<String, Cookie>();
		Cookie[] cookies = request.getCookies();
		if (null != cookies) {
			for (Cookie cookie : cookies) {
				cookieMap.put(cookie.getName(), cookie);
			}
		}
		return cookieMap;
	}
}
